#if !defined(glib_g2_stretched_rotation_h)
#define glib_g2_stretched_rotation_h

#include "vector.h"
//#include <cmath>

namespace g2 {

template <class T>
class basic_stretched_rotation;

typedef basic_stretched_rotation<double> stretched_rotation;
typedef basic_stretched_rotation<float> stretched_rotationf;
typedef basic_stretched_rotation<long double> stretched_rotationl;

//combination of scale and rotation, matrix of the form
//[ p -q ]
//[ q  p ]
template <class T>
class basic_stretched_rotation {
public:
    T p, q;
public:
	basic_stretched_rotation()
		{ }
	basic_stretched_rotation(T pp, T qq) : p(pp), q(qq)
		{ }
	template <class U> 
	basic_stretched_rotation(const basic_stretched_rotation<U> & v) : p(T(v.p)), q(T(v.q))
		{ } 
	basic_stretched_rotation & identity() 
		{ p = 1; q = 0; return * this; }
	basic_vector<T> operator ()(const basic_vector<T> & v) const 
		{ return basic_vector<T>(p * v.x - q * v.y, q * v.x + p * v.y);	}
	basic_vector<T> inverse(const basic_vector<T> & v) const ///< \return product of inverse stretched_rotation and given vector
		{ return 1 / det() * basic_vector<T>(p * v.x + q * v.y, -q * v.x + p * v.y);	}
	T det() const
		{ return p*p + q*q; }
	operator bool() const ///< returns true if not degenerate
		{ return p != 0 && q != 0; }
	basic_stretched_rotation<T> inverse() const {
		T rdet = 1 / det();
		return basic_stretched_rotation(rdet * p, -rdet * q);
	}
	T tr() const ///< trace of the matrix
		{ return 2 * p; }
public:
	bool operator == (const basic_stretched_rotation<T> & v) const
		{ return p == v.p && q == v.q; }
	bool operator != (const basic_stretched_rotation<T> & v) const
		{ return !(*this == v); }
};

template <class T>
inline basic_vector<T> operator * (const basic_stretched_rotation<T> & m, const basic_vector<T> & v) {
    return m(v);
}

///commutative!
template <class T>
inline basic_stretched_rotation<T> operator * (const basic_stretched_rotation<T> & lhs, const basic_stretched_rotation<T> & rhs) {
    return basic_stretched_rotation<T>(
		lhs.p * rhs.p - lhs.q * rhs.q, lhs.p * rhs.q + lhs.q * rhs.p);
}

} //namespace g2

#endif // glib_g2_stretched_rotation_h
